package load;


import annotation.DefinedLoadDataMethod;
import annotation.SoiComponent;
import annotation.SoiMethod;
import annotation.SoiScan;
import context.Holder;
import context.SoiHolder;
import context.SoiMethodHolder;
import exception.SoiRuntimeException;
import model.ExecuteMethod;
import util.AnnotationUtil;
import util.ClassLoaderUtil;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @className: AbstractDefaultSoiLoader
 * @author: ocxz1
 * @date: 2025/3/12 下午1:52
 * @Version: 1.0
 * @description: soi
 */
public abstract class AbstractDefaultSoiLoader implements SoiLoader {

    private final SoiMethodHolder soiNodeHolder = new SoiMethodHolder();

    private Class<?> applicationClass;

    private List<String> scanPathList;

    private List<String> excludePackageList;

    @Override
    public void init() {
        SoiScan annotation = getApplicationClass().getAnnotation(SoiScan.class);
        if (annotation != null) {
            scanPathList = new ArrayList<>();

            // 需要添加默认的
            scanPathList.add("load.impl.DefaultBeanLoader.class");

            excludePackageList = new ArrayList<>();
            scanPathList.addAll(List.of(annotation.scanPackages()));
            excludePackageList.addAll(List.of(annotation.excludePackages()));
        }

        // 资源加载
        loadResource();
    }

    @Override
    public Holder<String, ExecuteMethod> getHolder() {
        return soiNodeHolder;
    }

    @Override
    public void loadResource() {
        for (String scanPath : scanPathList) {
            try {
                List<Class<?>> classes = ClassLoaderUtil.loadClassesInPackage(scanPath, excludePackageList);

                classes.stream().filter(BeanLoader.class::isAssignableFrom)
                        .forEach(clazz -> {
                            try {
                                BeanLoader beanLoader = (BeanLoader) clazz.getDeclaredConstructor().newInstance();
                                SoiHolder.setBeanLoader(beanLoader);
                            } catch (Exception e) {
                                throw new SoiRuntimeException(e);
                            }
                        });

                for (Class<?> aClass : classes) {
                    SoiComponent soiComponent = AnnotationUtil.getAnnotation(aClass, SoiComponent.class);
                    if (soiComponent != null) {
                        Object beanName = AnnotationUtil.getAliasedValue(aClass, SoiComponent.class);
                        Object bean;
                        if (beanName == null || beanName.toString().isEmpty()) {
                            bean = SoiHolder.getBean(aClass);
                        } else {
                            bean = SoiHolder.getBean(beanName.toString());
                        }
                        Method[] methods = aClass.getMethods();
                        for (Method method : methods) {
                            SoiMethod soiMethod = AnnotationUtil.getAnnotation(method, SoiMethod.class);
                            if (soiMethod != null) {
                                String name = soiMethod.value();
                                if (name == null || name.isEmpty()) {
                                    name = method.getName();
                                }
                                getHolder().push(name, new ExecuteMethod(bean, method, soiMethod));
                            }

                            // 加载数据方法定义
                            DefinedLoadDataMethod loadDataMethod = AnnotationUtil.getAnnotation(method, DefinedLoadDataMethod.class);
                            if (loadDataMethod != null) {
                                String name = loadDataMethod.value();
                                if (name == null || name.isEmpty()) {
                                    name = aClass.getName() + "." + method.getName();
                                }
                                getHolder().push(name, new ExecuteMethod(bean, method, loadDataMethod));
                            }
                        }
                    }
                }
            } catch (Exception e) {
                throw new SoiRuntimeException(e);
            }
        }
    }

    @Override
    public Class<?> getApplicationClass() {
        return applicationClass;
    }

    @Override
    public SoiLoader setApplicationClass(Class<?> applicationClass) {
        this.applicationClass = applicationClass;
        return this;
    }
}
